#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

const std::string defaultpath = "/";
const std::string defaultdev = "/dev/null";
// 任何进程都可以通过 执行 setsid() 函数，把自己放进一个独立的会话中
// 但是这个进程不能是 进程组的组长

void Daemon(bool ischdir, bool isclose)
{
    // 1. 忽略不需要的信号
    signal(SIGCHLD, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);

    // 2. 确保不是进程组组长
    //    这步保证了调用Daemon这个函数的进程总是成为孤儿进程后，
    //    被1号进程(即系统)领养
    if (fork() > 0 )
    {
        exit(0);
    }

    // 3. setsid
    setsid();

    // 4. 确认是否要更改工作目录
    if (ischdir)
    {
        // 如果更改，调用这个函数之后的代码如果要创建文件等操作，
        // 将会在 defaultpath 这个路径下进行的
        chdir(defaultpath.c_str());
    }

    // 5. 对 0 1 2 文件描述符进行重定向，防止新的会话 会将自己运行的内容打印到这些文件中
    if (isclose)
    {
        ::close(0);
        ::close(1);
        ::close(2);
    }
    else
    {
        // 此程序中"/dev/null" 是默认路径
        // 利用 dup2 将0, 1, 2 这三个文件描述符进行重定向之后
        // 如果有任何想要打印到 这三个文件描述符中的内容，都将被丢弃
        int fd = open(defaultdev.c_str(), O_RDWR);
        if (fd > 0)
        {
            dup2(fd, 0);
            dup2(fd, 1);
            dup2(fd, 2);
        }
        
    }

}
